package com.billlv.codegenerator.common.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
import java.util.stream.Collectors;

@Component
public class JwtUtils {

    private final PrivateKey privateKey;
    private final PublicKey publicKey;

    @Value("${jwt.access-token-expiration}")
    private long accessTokenExpirationMs;

    @Value("${jwt.refresh-token-expiration}")
    private long refreshTokenExpirationMs;

    @Value("${jwt.issuer}")
    private String issuer;

    @Value("${jwt.audience}")
    private String audience;

    public JwtUtils(@Value("${jwt.private-key}") String privateKeyPath,
                    @Value("${jwt.public-key}") String publicKeyPath) throws Exception {
        this.privateKey = loadPrivateKey(privateKeyPath);
        this.publicKey = loadPublicKey(publicKeyPath);
    }

    // 读取私钥
    public PrivateKey loadPrivateKey(String privateKeyPath) throws Exception {
        try (InputStream inputStream = new FileInputStream(privateKeyPath)) {
            // 使用 BufferedReader 手动读取文件内容
            String privateKeyContent = new BufferedReader(new InputStreamReader(inputStream))
                    .lines()
                    .collect(Collectors.joining("\n"))
                    .replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", ""); // 移除所有空格和换行

            // Base64 解码
            byte[] keyBytes = Base64.getDecoder().decode(privateKeyContent);

            // 使用 PKCS8 规范解析私钥
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            return keyFactory.generatePrivate(keySpec);
        }
    }

    // 读取公钥
    public PublicKey loadPublicKey(String publicKeyPath) throws Exception {
        try (InputStream inputStream = new FileInputStream(publicKeyPath)) {
            // 使用 BufferedReader 手动读取文件内容
            String publicKeyContent = new BufferedReader(new InputStreamReader(inputStream))
                    .lines()
                    .collect(Collectors.joining("\n"))
                    .replace("-----BEGIN PUBLIC KEY-----", "")
                    .replace("-----END PUBLIC KEY-----", "")
                    .replaceAll("\\s+", ""); // 移除所有空格和换行

            // Base64 解码
            byte[] keyBytes = Base64.getDecoder().decode(publicKeyContent);

            // 使用 X509 规范解析公钥
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            return keyFactory.generatePublic(keySpec);
        }
    }

    public String generateAccessToken(String userId) {
        String tokenId = UUID.randomUUID().toString(); // 生成唯一 ID
        return Jwts.builder()
                .setId(tokenId)
                .setSubject(userId)
                .setIssuer(issuer)
                .setAudience(audience)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + accessTokenExpirationMs))
                .signWith(SignatureAlgorithm.RS256, privateKey) // JDK 1.8 适配
                .compact();
    }

    public String generateRefreshToken(String userId) {
        String tokenId = UUID.randomUUID().toString(); // 生成唯一 ID
        return Jwts.builder()
                .setId(tokenId)
                .setSubject(userId)
                .setIssuer(issuer)
                .setAudience(audience)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + refreshTokenExpirationMs))
                .signWith(SignatureAlgorithm.RS256, privateKey) // JDK 1.8 适配
                .compact();
    }


    public String getTokenId(String token) {
        // 解析 JWT Token
        Claims claims = Jwts.parser()
                .setSigningKey(publicKey) // 使用公钥验证签名
                .parseClaimsJws(token)
                .getBody();
        // 提取 tokenId
        return claims.getId(); // 获取 setId() 设置的 tokenId
    }

    public Date getExpirationTime(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(publicKey) // 使用公钥验证签名
                .parseClaimsJws(token)
                .getBody();

        return claims.getExpiration(); // 提取 exp 字段，返回过期时间
    }



    public String getUserIdFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(publicKey)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    public boolean validateJwtToken(String token) {
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(publicKey)
                    .parseClaimsJws(token)
                    .getBody();

            // 校验标准字段
            if (!issuer.equals(claims.getIssuer()) || !audience.equals(claims.getAudience())) {
                throw new IllegalArgumentException("Invalid token claims");
            }
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            // 记录日志
            System.err.println("Invalid JWT token: " + e.getMessage());
        }
        return false;
    }
}
